package com.wyz.saas.common.utils

import android.content.Context
import android.graphics.*
import android.graphics.drawable.Drawable
import android.text.Editable
import android.text.Spannable
import android.text.SpannableString
import android.text.TextUtils
import android.text.style.DynamicDrawableSpan
import android.text.style.ImageSpan
import android.util.ArrayMap
import android.view.View
import androidx.annotation.NonNull
import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.SimpleTarget
import com.bumptech.glide.request.transition.Transition
import com.wyz.saas.common.R
import java.io.File
import java.io.FileReader
import java.io.IOException
import java.nio.charset.Charset
import java.util.*
import java.util.regex.Pattern
import java.util.zip.ZipEntry
import java.util.zip.ZipFile
import kotlin.collections.ArrayList


class FaceFactory {
    companion object {
        // 全局的表情的映射ArrayMap，更加轻量级
        private val FACE_MAP: ArrayMap<String, Bean> = ArrayMap()
        private var FACE_TABS: List<FaceTab>? = null

        private fun init(context: Context): List<FaceTab> {
            if (FACE_TABS == null) {
                synchronized(FaceFactory::class.java) {
                    if (FACE_TABS == null) {
                        val faceTabs: ArrayList<FaceTab> = ArrayList()
                        initAssetsFace(
                            context
                        )?.also { faceTabs.add(it) }
                        initResourceFace(
                            context
                        )?.also { faceTabs.add(it) }
                        // init map
                        for (faceTab in faceTabs) {
                            faceTab.copyToMap(FACE_MAP)
                        }
                        // init list 不可变的集合
                        FACE_TABS = Collections.unmodifiableList(faceTabs)
                    }
                }
            }
            return FACE_TABS!!
        }

        // 从face-t.zip包解析我们的表情
        private fun initAssetsFace(context: Context): FaceTab? {
            val faceAsset = "face-t.zip"
            // data/user/0/com.wyz.im/files/face/tf
            val faceCacheDir = String.format("%s/face/tf", context.filesDir)
            val faceFolder = File(faceCacheDir)
            if (!faceFolder.exists()) {
                // 不存在进行初始化
                if (faceFolder.mkdirs()) {
                    try {
                        val inputStream = context.assets.open(faceAsset) // 获取表情
                        // 存储文件
                        val faceSource = File(faceFolder, "source.zip") // 进行拷贝
                        // copy
                        StreamUtil.copy(inputStream, faceSource) // 进行拷贝
                        // 解压
                        unZipFile(
                            faceSource,
                            faceFolder
                        ) // 解压
                        // 清理文件
                        StreamUtil.delete(faceSource.absolutePath) // 删除
                    } catch (e: IOException) {
                        e.printStackTrace()
                    }
                }
            }
            // info.json
            val infoFile = File(faceCacheDir, "info.json")
            // Gson
            val gson = JacksonUtils.objectMapper()
            // 解析
            val tab: FaceTab = gson.readValue(FileReader(infoFile), FaceTab::class.java)

            // 相对路径到绝对路径
            for (face in tab.faces) {
                face.preview = String.format(
                    "%s/%s", faceCacheDir,
                    face.preview
                )
                face.source = String.format(
                    "%s/%s", faceCacheDir,
                    face.source
                )
            }
            return tab
        }

        // 把zipFile解压到desDir目录
        @Throws(IOException::class)
        private fun unZipFile(zipFile: File, desDir: File) {
            val folderPath: String = desDir.absolutePath
            val zf = ZipFile(zipFile)
            // 判断节点进行循环
            val entries: Enumeration<*> = zf.entries()
            while (entries.hasMoreElements()) {
                val entry = entries.nextElement() as ZipEntry
                // 过滤缓存的文件
                val name: String = entry.name
                if (name.startsWith(".")) {
                    continue
                }

                // 输入流
                val `in` = zf.getInputStream(entry)
                var str = folderPath + File.separator.toString() + name

                // 防止名字错乱
                str = String(str.toByteArray(charset("8859_1")), Charset.forName("GB2312"))
                val desFile = File(str)
                // 输出文件
                StreamUtil.copy(`in`, desFile)
            }
        }

        // 从drawable资源中加载数据并映射到对应的key
        private fun initResourceFace(context: Context): FaceTab? {
            val faces: ArrayList<Bean> = ArrayList()
            val resources = context.resources
            val packageName = context.applicationInfo.packageName
            for (i in 1..142) {
                // i=1=>  001
                val key = java.lang.String.format(Locale.ENGLISH, "fb%03d", i)
                val resStr = java.lang.String.format(Locale.ENGLISH, "face_base_%03d", i)
                // 根据资源名称去拿资源对应的ID
                val resId: Int = resources.getIdentifier(resStr, "drawable", packageName)
                if (resId == 0) continue
                // 添加表情
                faces.add(Bean(key, resId))
            }
            return if (faces.size == 0) null else FaceTab(
                "NAME",
                faces[0].preview,
                faces
            )
        }

        // 获取所有的表情
        fun all(@NonNull context: Context): List<FaceTab> {
            return init(context)
        }

        // 输入表情到editable
        fun inputFace(
            @NonNull context: Context, editable: Editable,
            bean: Bean?, size: Int
        ) {
            Glide.with(context)
                .load(bean!!.preview)
                .into(object : SimpleTarget<Drawable>() {
                    override fun onResourceReady(
                        resource: Drawable,
                        transition: Transition<in Drawable>?
                    ) {
                        val spannable: Spannable =
                            SpannableString(java.lang.String.format("[%s]", bean.key))
                        val span =
                            ImageSpan(context,
                                drawableToBitmap(
                                    resource
                                ), ImageSpan.ALIGN_BASELINE)
                        // 前后不关联
                        spannable.setSpan(
                            span,
                            0,
                            spannable.length,
                            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
                        )
                        editable.append(spannable)
                    }
                })
        }

        fun drawableToBitmap(drawable: Drawable): Bitmap {
            val bitmap = Bitmap.createBitmap(
                drawable.intrinsicWidth, drawable.intrinsicHeight,
                if (drawable.opacity != PixelFormat.OPAQUE) Bitmap.Config.ARGB_8888 else Bitmap.Config.RGB_565
            )
            val canvas = Canvas(bitmap)
            drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight)
            drawable.draw(canvas)
            return bitmap
        }

        // 从spannable解析表情并替换显示
        fun decode(target: View, spannable: Spannable?, size: Int): Spannable? {
            if (spannable == null) return null
            val str = spannable.toString()
            if (TextUtils.isEmpty(str)) return null
            val context = target.context

            // 进行正在匹配[][][]
            val pattern = Pattern.compile("(\\[[^\\[\\]:\\s\\n]+\\])")
            val matcher = pattern.matcher(str)
            while (matcher.find()) {
                // [ft112]
                val key: String = matcher.group()
                if (TextUtils.isEmpty(key)) continue
                val bean = get(
                    context,
                    key.replace("[", "").replace("]", "")
                ) ?: continue
                val start: Int = matcher.start()
                val end: Int = matcher.end()

                // 得到一个复写后的标示
                val span: ImageSpan = FaceSpan(
                    context,
                    target,
                    bean.preview,
                    size
                )
                // 设置标示
                spannable.setSpan(span, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
            }
            return spannable
        }


        // 拿一个Bean
        // key: ft001
        operator fun get(context: Context, key: String?): Bean? {
            init(context)
            return if (FACE_MAP.containsKey(key)) {
                FACE_MAP[key]
            } else null
        }

    }

    // 表情标示
    class FaceSpan : ImageSpan {
        // 自己真实绘制的
        private var mDrawable: Drawable? = null
        private var mView: View? = null
        private var mSize = 0
        /**
         * 构造
         * @param context 上下文
         * @param view    目标View，用于加载完成时刷新使用
         * @param source  加载目标
         * @param size    图片的显示大小
         */
        constructor(
            context: Context,
            view: View,
            source: Any?,
            size: Int
        ) : super(context, R.drawable.default_face, DynamicDrawableSpan.ALIGN_BOTTOM) {
            // 虽然设置了默认的表情，但是并不显示，只是用于占位
            mView = view
            mSize = size
            Glide.with(context)
                .load(source)
                .fitCenter()
                .into(object : SimpleTarget<Drawable>(size, size) {
                    override fun onResourceReady(
                        resource: Drawable,
                        transition: Transition<in Drawable>?
                    ) {
                        mDrawable = resource.current
                        // 获取自测量高宽
                        val width = mDrawable!!.intrinsicWidth
                        val height = mDrawable!!.intrinsicHeight
                        // 设置进去
                        mDrawable!!.setBounds(
                            0, 0, if (width > 0) width else size,
                            if (height > 0) height else size
                        )
                        // 通知刷新
                        mView!!.invalidate()
                    }

                })
        }

        override fun getSize(
            paint: Paint,
            text: CharSequence?,
            start: Int,
            end: Int,
            fm: Paint.FontMetricsInt?
        ): Int {
            // 走我们自己的逻辑，进行测量
            val rect = if (mDrawable != null) mDrawable!!.bounds else Rect(0, 0, mSize, mSize)
            if (fm != null) {
                fm.ascent = -rect.bottom
                fm.descent = 0
                fm.top = fm.ascent
                fm.bottom = 0
            }
            return rect.right
        }

        override fun getDrawable(): Drawable {
            // 复写拿Drawable的方法，当然这里有可能返回的是null
            return mDrawable!!
        }

        override fun draw(
            canvas: Canvas,
            text: CharSequence?,
            start: Int,
            end: Int,
            x: Float,
            top: Int,
            y: Int,
            bottom: Int,
            paint: Paint
        ) {
            // 增加判断
            if (mDrawable != null) super.draw(canvas, text, start, end, x, top, y, bottom, paint)
        }

    }


    /**
     * 每一个表情盘，含有很多表情
     */
    class FaceTab {
        var faces: List<Bean> = ArrayList()
        var name: String? = null
        // 预览图, 包括了drawable下面的资源int类型
        var preview: Any? = null

        constructor()

        constructor(
            name: String,
            preview: Any?,
            faces: List<Bean>
        ) {
            this.faces = faces
            this.name = name
            this.preview = preview
        }

        // 添加到Map
        fun copyToMap(faceMap: ArrayMap<String, Bean>) {
            for (face in faces) {
                faceMap[face.key] = face
            }
        }
    }

    /**
     * 每一个表情
     */
    class Bean {
        var key: String? = null
        var desc: String? = null
        var source: Any? = null
        var preview: Any? = null

        constructor()

        constructor(key: String, preview: Int) {
            this.key = key
            this.source = preview
            this.preview = preview
        }
    }
}